package tests.Modelo;

import static org.junit.Assert.*;
import java.util.Calendar;
import modelo.OfertaBuilder;
import modelo.OfertasRepository;
import modelo.Producto;
import modelo.ProductosRepository;
import modelo.Venta;
import modelo.acciones.AccionOfertaFactory;
import modelo.condiciones.CondicionOfertaFactory;
import static org.mockito.Mockito.mock;
import org.junit.Before;
import org.junit.Test;

public class VentaTests {
	
	private OfertasRepository ofertaRepositorio;

	@Before
	public void doBefore()
	{
	    ofertaRepositorio = mock(OfertasRepository.class);
	}

	@Test
	public void tieneDeUnTipoDeProductoTest() {
		//creo un producto.
		Producto producto = new Producto("Test", 1, 1, "test", "test");
		//Creo una venta.
		Venta venta = new Venta(ofertaRepositorio, Calendar.getInstance(), 1);
		//Agrego el producto a la venta.
		venta.addProducto(producto, 1);
		//Verifico que el producto este en la venta.
		assertTrue(venta.tieneDeUnTipoDeProducto(producto, 1));		
	}

	@Test
	public void hasCategoriaTest() {
		String categoria = "categoriaTest";
		//creo un producto.
		Producto producto = new Producto("Test", 1, 1, categoria, "test");
		//Creo una venta.
		Venta venta = new Venta(ofertaRepositorio, Calendar.getInstance(), 1);
		//Agrego el producto a la venta.
		venta.addProducto(producto, 1);
		//Verifico que el producto este en la venta.
		assertTrue(venta.hasCategoria(categoria, 1));		
	}
	
	@Test
	public void hasMarcaTest() {
		String marca = "marcaTest";
		//creo un producto.
		Producto producto = new Producto("Test", 1, 1, "test", marca);
		//Creo una venta.
		Venta venta = new Venta(ofertaRepositorio, Calendar.getInstance(), 1);
		//Agrego el producto a la venta.
		venta.addProducto(producto, 1);
		//Verifico que el producto este en la venta.
		assertTrue(venta.hasMarca(marca));		
	}
	
	@Test
	public void aplicarDescuentoPorCategoriaTest() {
		String categoria = "categoriaTest";
		//creo un producto.
		Producto producto = new Producto("Test", 1, 1, categoria, "test");
		//Creo una venta.
		Venta venta = new Venta(ofertaRepositorio, Calendar.getInstance(), 1);
		//Agrego el producto a la venta.
		venta.addProducto(producto, 1);

		int cantidadOfertasAplicadas = venta.getOfertasAplicadas().size();
		venta.aplicarDescuentoPorCategoria(categoria, null, 0.1,"OfertaTest");
		
		assertTrue(cantidadOfertasAplicadas == venta.getOfertasAplicadas().size() - 1);
	}
	
	@Test
	//Testea una venta con descuento levando n prods iguales, pagas M < N
	public void ventaConOfertaLlevaNpagaMTest() 
	{
		double precio = 10;
		Calendar ofertaDesde;
		Calendar ofertaHasta;
	
		//Creo un producto con precio $10
		ProductosRepository productos = new ProductosRepository();
		productos.addProducto(new Producto("Coca Cola", precio, 1, "Bebidas", "Coca Cola Company"));
		
		ofertaDesde = Calendar.getInstance();
		ofertaHasta = Calendar.getInstance();		
		ofertaHasta.add(Calendar.MONTH, 1);		
		
		AccionOfertaFactory accionOfertaFactory = new AccionOfertaFactory();
		CondicionOfertaFactory condicionOfertaFactory = new CondicionOfertaFactory();
		OfertaBuilder ofertaBuilder = new OfertaBuilder();
		
		//Creo una nueva oferta
		ofertaBuilder.crearNuevaOferta(ofertaDesde, ofertaHasta, "2x1 Coca Cola");
		//Le agrego la condicion de que si lleva dos de un producto.
		ofertaBuilder.agregarCondicion(condicionOfertaFactory.CondicionLlevaNProducto(productos.getProductoByDetalle("Coca Cola"), 2));
		//Le descuenta una unidad.
		ofertaBuilder.agregarAccion(accionOfertaFactory.AccionDescontarDeProducto(productos.getProductoByDetalle("Coca Cola"), 1, 1));
		OfertasRepository ofertas = new OfertasRepository();
		//Cargo la oferta al repositorio de ofertas.
		ofertas.addOferta(ofertaBuilder.getOferta());
		
		//Creo la venta
		Venta venta = new Venta(ofertas, Calendar.getInstance(), 1);
		//Y le cargo 2 unidades del producto de la promo 2X1
		venta.addProducto(productos.getProductoById(1), 2);
		
		//Dado que hay una promocion 2X1 para un producto, cuando lleva ese prodcuto, entonces paga solo 1 de los 2.
		//El precio del produco es $10, lleva 2, esta en promo. Paga $10.
		assertEquals(venta.getTotal(), precio,1);
	}
	
	@Test
	//Testa una venta con descuento llevando productos de N y productos M, entonces hay un descuento en el producto Z.
	public void ventaConOfertaLlevandoNyMpagaMenosElZTest() 
	{
		double precioCoca = 10;
		double precioSprite = 20;
		double precioFanta = 30;
		Calendar ofertaDesde;
		Calendar ofertaHasta;
	
		//Creo un producto con precio $10
		ProductosRepository productos = new ProductosRepository();
		productos.addProducto(new Producto("Coca Cola", precioCoca, 1, "Bebidas", "Coca Cola Company"));
		productos.addProducto(new Producto("Sprite", precioSprite, 2, "Bebidas", "Coca Cola Company"));
		productos.addProducto(new Producto("Fanta", precioFanta, 3, "Bebidas", "Coca Cola Company"));
		
		ofertaDesde = Calendar.getInstance();
		ofertaHasta = Calendar.getInstance();		
		ofertaHasta.add(Calendar.MONTH, 1);		
		
		AccionOfertaFactory accionOfertaFactory = new AccionOfertaFactory();
		CondicionOfertaFactory condicionOfertaFactory = new CondicionOfertaFactory();
		OfertaBuilder ofertaBuilder = new OfertaBuilder();
		
		//Creo una nueva oferta
		ofertaBuilder.crearNuevaOferta(ofertaDesde, ofertaHasta, "Coca + Sprite = Fanta al 50%");
		//Le agrego la condicion de que si lleva dos de un producto.
		ofertaBuilder.agregarCondicion(condicionOfertaFactory.CondicionLlevaNProducto(productos.getProductoByDetalle("Coca Cola"), 1));
		ofertaBuilder.agregarCondicion(condicionOfertaFactory.CondicionLlevaNProducto(productos.getProductoByDetalle("Sprite"), 1));
		ofertaBuilder.agregarCondicion(condicionOfertaFactory.CondicionLlevaNProducto(productos.getProductoByDetalle("Fanta"), 1));
		//Le descuenta la mitad a una unidad.
		ofertaBuilder.agregarAccion(accionOfertaFactory.AccionDescontarDeProducto(productos.getProductoByDetalle("Fanta"), 1, 0.5));
		OfertasRepository ofertas = new OfertasRepository();
		//Cargo la oferta al repositorio de ofertas.
		ofertas.addOferta(ofertaBuilder.getOferta());
		
		//Creo la venta
		Venta venta = new Venta(ofertas, Calendar.getInstance(), 1);
		//Y le cargo 1 unidades de cada uno de los prods de la promo
		venta.addProducto(productos.getProductoById(1), 1);
		venta.addProducto(productos.getProductoById(2),1);
		venta.addProducto(productos.getProductoById(3), 1);
		
		//Dado que hay una promocion Cocal + Sprite = Fanta al 50%, cuando lleva esos 3 productos prodcuto, entonces paga la fanta al 50%
		assertEquals(venta.getTotal(), precioCoca+precioSprite+(precioFanta/2),1);
				
	}
	
	@Test
	//Testea una venta con descuento por marca: Llevando algun producto de una marca dada, hay un descuento de algun porcentaje.
	public void ventaConOfertaPorMarcaTest() 
	{
		double precioCoca = 10;
		double precioSprite = 20;
		double precioFanta = 30;
		Calendar ofertaDesde;
		Calendar ofertaHasta;
		String marca = "Coca Cola Company";
	
		//Creo un producto con precio $10
		ProductosRepository productos = new ProductosRepository();
		productos.addProducto(new Producto("Coca Cola", precioCoca, 1, "Bebidas", marca));
		productos.addProducto(new Producto("Sprite", precioSprite, 2, "Bebidas", marca));
		productos.addProducto(new Producto("Fanta", precioFanta, 3, "Bebidas", marca));
		
		ofertaDesde = Calendar.getInstance();
		ofertaHasta = Calendar.getInstance();		
		ofertaHasta.add(Calendar.MONTH, 1);		
		
		AccionOfertaFactory accionOfertaFactory = new AccionOfertaFactory();
		CondicionOfertaFactory condicionOfertaFactory = new CondicionOfertaFactory();
		OfertaBuilder ofertaBuilder = new OfertaBuilder();
		
		//Creo una nueva oferta
		ofertaBuilder.crearNuevaOferta(ofertaDesde, ofertaHasta, "Marca Coca Cola con 50% de descuento");
		//Le agrego la condicion de que si lleva dos de un producto.
		ofertaBuilder.agregarCondicion(condicionOfertaFactory.CondicionMarcaProducto(marca));
		//Le descuenta la mitad a los productos de la marca.
		ofertaBuilder.agregarAccion(accionOfertaFactory.AccionDescontarPorMarca(marca, null, 0.5));
		OfertasRepository ofertas = new OfertasRepository();
		//Cargo la oferta al repositorio de ofertas.
		ofertas.addOferta(ofertaBuilder.getOferta());
		
		//Creo la venta
		Venta venta = new Venta(ofertas, Calendar.getInstance(), 1);
		//Y le cargo 3 productos de la marca.
		venta.addProducto(productos.getProductoById(1), 1);
		venta.addProducto(productos.getProductoById(2),1);
		venta.addProducto(productos.getProductoById(3), 1);
		
		//Dado que hay una promocion tal que hace el 50% de desc a todos los prods de la marca Coca Cola, 
		//cuando lleva 3 productos de $10, $20 y $30
		//Entonces solo debe cobrar la mitdad de cada uno: $30
		assertEquals(venta.getTotal(), precioCoca/2+precioSprite/2+precioFanta/2,1);
				
	}
	
	@Test
	//Testea una venta con oferta de pagando con un medio de pago dado (Efectivo en este caso) hay un descuento de algun porcentaje.
	public void ventaConOfertaPorMedioDePagoTest() 
	{
		double precioCoca = 10;
		double precioSprite = 20;
		double precioFanta = 30;
		Calendar ofertaDesde;
		Calendar ofertaHasta;
		String medioPago = "Efectivo";
		double descuento = 0.1;
	
		//Creo un producto con precio $10
		ProductosRepository productos = new ProductosRepository();
		productos.addProducto(new Producto("Coca Cola", precioCoca, 1, "Bebidas", "Coca"));
		productos.addProducto(new Producto("Sprite", precioSprite, 2, "Bebidas", "Coca"));
		productos.addProducto(new Producto("Fanta", precioFanta, 3, "Bebidas", "Coca"));
		
		ofertaDesde = Calendar.getInstance();
		ofertaDesde.add(Calendar.MONTH, -1);		
		ofertaHasta = Calendar.getInstance();		
		ofertaHasta.add(Calendar.MONTH, 1);		
		
		AccionOfertaFactory accionOfertaFactory = new AccionOfertaFactory();
		CondicionOfertaFactory condicionOfertaFactory = new CondicionOfertaFactory();
		OfertaBuilder ofertaBuilder = new OfertaBuilder();
		
		//Creo una nueva oferta
		ofertaBuilder.crearNuevaOferta(ofertaDesde, ofertaHasta, "10% Pago en Efectivo");
		//Le agrego la condicion de que si paga con el medio de la oferta.
		ofertaBuilder.agregarCondicion(condicionOfertaFactory.CondicionMedioDePago(medioPago));
		//Le descuenta el porcentaje de la oferta.
		ofertaBuilder.agregarAccion(accionOfertaFactory.AccionDescontarDeVentaCompleta(descuento));
		OfertasRepository ofertas = new OfertasRepository();
		//Cargo la oferta al repositorio de ofertas.
		ofertas.addOferta(ofertaBuilder.getOferta());
		
		//Creo la venta
		Venta venta = new Venta(ofertas, Calendar.getInstance(), 1);
		//Y le cargo 3 productos de la marca.
		venta.addProducto(productos.getProductoById(1), 1);
		venta.addProducto(productos.getProductoById(2),1);
		venta.addProducto(productos.getProductoById(3), 1);
		venta.cobrar(medioPago);
		
		//Dado que hay una promocion tal que hace el 10% de desc a todos los prods si se paga con efectivo, 
		//cuando lleva 3 productos de $10, $20 y $30
		//Entonces debe cobrar $5+$10+$15=$30
		assertEquals(precioCoca-(precioCoca * 0.1)+precioSprite-(precioSprite * 0.1)+precioFanta - (precioFanta*0.1), venta.getTotal(),1);
				
	}
}


